#include <string.h>
#include <iostream>
using std::cout;
using std::endl;
using std::ostream;


class CowString
{
    //设计模式之代理模式
    //专为CowString来服务的
    class CharProxy
    {
    public:
        CharProxy(int idx, CowString & self)
        : _idx(idx)
        , _self(self)
        {}

        char & operator=(char ch);

        //访问CharProxy的私有成员
        friend ostream & operator<<(ostream&, const CharProxy &);
    private:
        int _idx;
        CowString & _self;
    };
    //CharProxy是CowString的私有类型
    friend ostream & operator<<(ostream&, const CharProxy &);
public:
    CowString()
    : _pstr(new char[5]() + 4)
    {   
        cout << "CowString()" << endl;  
        //初始化引用计数
        initRefcount();
    }

    CowString(const char * pstr)
    : _pstr(new char[strlen(pstr) + 5]() + 4)
    {
        cout << "CowString(const char*)" << endl;
        strcpy(_pstr, pstr);
        initRefcount();
    }

    ~CowString()
    {
        release();
    }


    //时间复杂度为O(1)
    CowString(const CowString & rhs)
    : _pstr(rhs._pstr)//浅拷贝
    {
        cout << "CowString(const CowString&)" << endl;
        increaseRefcount();
    }

    CowString & operator=(const CowString & rhs)
    {
        cout << "CowString & operator=(const CowString&)" << endl;
        if(this != &rhs) {
            release();//回收左操作数空间
            //浅拷贝, 引用计数加1
            _pstr = rhs._pstr;
            increaseRefcount();
        }
        return *this;
    }

    //下标访问运算符必须要返回一个自定义类类型
    //CharProxy
    //char & operator[](size_t idx);
    CharProxy operator[](size_t idx);

    const char * c_str() const {    return _pstr;   }

    int size() const {  return strlen(_pstr);   }
    
    int getRefcount() const { return *(int*)(_pstr - 4);     }

    friend ostream & operator<<(ostream & os, const CowString & rhs);
private:
    void initRefcount() {
        *(int*)(_pstr - 4) = 1;
    }

    void increaseRefcount() {
       ++*(int*)(_pstr - 4);
    }

    void decreaseRefcount() {
       --*(int*)(_pstr - 4);
    }

    void release()
    {
        decreaseRefcount();
        if(getRefcount() == 0) {
            delete [] (_pstr - 4);
            cout << ">> free heap space" << endl;
        }
    }

private:
    char * _pstr;
};

ostream & operator<<(ostream & os, const CowString & rhs)
{
    os << rhs._pstr;
    return os;
}

//实现读操作
ostream & operator<<(ostream & os, const CowString::CharProxy & rhs)
{
    os << rhs._self._pstr[rhs._idx];
    return os;
}

CowString::CharProxy CowString::operator[](size_t idx)
{
    return CharProxy(idx, *this);
}

//实现写操作
char & CowString::CharProxy::operator=(char ch)
{
    if(_idx < _self.size()) {
        //判断是否为共享字符串
        if(_self.getRefcount() > 1){
            _self.decreaseRefcount();
            char * ptmp = new char[_self.size() + 5]() + 4;
            strcpy(ptmp, _self._pstr);
            _self._pstr = ptmp;
            _self.initRefcount();
        }
        _self._pstr[_idx] = ch;
        return _self._pstr[_idx];
    }else {
        static char nullchar = '\0';
        return nullchar;
    }
}

//问题的难点：先获取s1[0], 
//获取到s1[0]之后，要做读和写，是下标访问运算符无法预料的
#if 0
char & CowString::operator[](size_t idx)
{
    if(idx < size()) {
        //判断是否为共享字符串
        if(getRefcount() > 1){
            decreaseRefcount();
            char * ptmp = new char[size() + 5]() + 4;
            strcpy(ptmp, _pstr);
            _pstr = ptmp;
            initRefcount();
        }
        return _pstr[idx];
    }else {
        static char nullchar = '\0';
        return nullchar;
    }
}
#endif

void test0()
{
    CowString s0;
    cout << "s0:" << s0 << endl;
    CowString s1("hello");
    cout << "s1:" << s1 << endl;

    CowString s2 = s1;
    cout << "s2:" << s2 << endl;
    printf("s1's content address: %p\n", s1.c_str());
    printf("s2's content address: %p\n", s2.c_str());
    cout << "s1' refcount:" << s1.getRefcount() << endl;
    cout << "s2' refcount:" << s2.getRefcount() << endl;


    CowString s3("world");
    cout << "s3:" << s3 << endl;
    cout << "s3' refcount:" << s3.getRefcount() << endl;

    cout << "\n赋值运算符 s3 = s1:" << endl;
    s3 = s1;
    cout << "s3:" << s3 << endl;
    printf("s1's content address: %p\n", s1.c_str());
    printf("s2's content address: %p\n", s2.c_str());
    printf("s3's content address: %p\n", s3.c_str());
    cout << "s1' refcount:" << s1.getRefcount() << endl;
    cout << "s2' refcount:" << s2.getRefcount() << endl;
    cout << "s3' refcount:" << s3.getRefcount() << endl;

    cout << "\n执行写操作s3[0] = 'H' :" << endl;
    s3[0] = 'H';
    printf("&s1: %p\n", &s1);
    printf("&s2: %p\n", &s2);
    printf("&s3: %p\n", &s3);
    printf("s1's content address: %p\n", s1.c_str());
    printf("s2's content address: %p\n", s2.c_str());
    printf("s3's content address: %p\n", s3.c_str());
    cout << "s1' refcount:" << s1.getRefcount() << endl;
    cout << "s2' refcount:" << s2.getRefcount() << endl;
    cout << "s3' refcount:" << s3.getRefcount() << endl;
    cout << "s3:" << s3 << endl;

#if 1
    cout << "\n执行读操作s1[0]:" << endl;
    cout << "s1[0]:" << s1[0] << endl;
    printf("s1's content address: %p\n", s1.c_str());
    printf("s2's content address: %p\n", s2.c_str());
    printf("s3's content address: %p\n", s3.c_str());
    cout << "s1' refcount:" << s1.getRefcount() << endl;
    cout << "s2' refcount:" << s2.getRefcount() << endl;
    cout << "s3' refcount:" << s3.getRefcount() << endl;
#endif
}


int main()
{
    test0();
    return 0;
}

